package com.jiakai.cashinterfacemucon.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
//import com.jkzn.common.advice.ExceptionEnum;
//import com.jkzn.common.advice.JkznException;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Description
 * @ClassName JsonUtil
 * @Author CX
 * @Date 2018/12/5 9:11
 */
public class JsonUtil {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    static{
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
    }

    /**
     * 对象转json
     * @param object
     * @return
     */
    public static String objectConverString(Object object){
        if(object == null){
            return null;
        }
        if(object.getClass() == String.class ){
            return (String) object;
        }
        try {
            return objectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
//            throw new JkznException(ExceptionEnum.JSON_PARSE_FAIL);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * Json转对象
     * @param json
     * @param clazz
     * @param <E>
     * @return
     */
    public static <E> E jsonStrconverObject(String json,Class<E> clazz){
        try {
            return objectMapper.readValue(json,clazz);
        } catch (IOException e) {
//            throw new JkznException(ExceptionEnum.JSON_PARSE_FAIL);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * Json转List
     * @param json
     * @param clazz
     * @param <E>
     * @return
     */
    public static <E> List<E> jsonStrConverList(String json,Class<E> clazz){
        try {
            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY,true);
            return objectMapper.readValue(json, getJavaType(List.class,clazz));
        } catch (IOException e) {
//            throw new JkznException(ExceptionEnum.JSON_PARSE_FAIL);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * Json转Map
     * @param json
     * @param kclazz
     * @param vclazz
     * @param <K>
     * @param <V>
     * @return
     */
    public static <K,V> Map<K,V> jsonStrConverMap(String json,Class<K> kclazz,Class<V> vclazz){
        try {
            return objectMapper.readValue(json, getJavaType(Map.class, kclazz, vclazz));
        } catch (IOException e) {
//            throw new JkznException(ExceptionEnum.JSON_PARSE_FAIL);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * Map转对象
     * @param map
     * @param clazz
     * @param <E>
     * @return
     */
    public static <E> E mapConverObject(Map map,Class<E> clazz){
        return objectMapper.convertValue(map,clazz);
    }

    /**
     * Map转Json字符串
     * @param map
     * @return
     */
    public static String mapConverString(Map map){
        try {
            return objectMapper.writeValueAsString(map);
        } catch (JsonProcessingException e) {
//            throw new JkznException(ExceptionEnum.JSON_PARSE_FAIL);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 把json解析成list，如果list内部的元素存在jsonString，继续解析
     *
     * @param json
     * @param mapper 解析工具
     * @return
     * @throws Exception
     */
    private static List<Object> depthConverList(String json, ObjectMapper mapper) throws Exception {
        if (json == null) {
            return null;
        }
        List<Object> list = mapper.readValue(json, List.class);
        for (Object obj : list) {
            if (obj != null && obj instanceof String) {
                String str = (String) obj;
                if (str.startsWith("[")) {
                    obj = depthConverList(str, mapper);
                } else if (obj.toString().startsWith("{")) {
                    obj = depthConverMap(str, mapper);
                }
            }
        }
        return list;
    }

    /**
     * 把JSON解析成Map，如果map内部的value存在jsonString，继续解析
     * @param json
     * @param mapper
     * @return
     * @throws Exception
     */
    public static Map<String,Object> depthConverMap(String json,ObjectMapper mapper) throws Exception {

        if(json == null){
            return null;
        }

        Map<String,Object> map = mapper.readValue(json,Map.class);
        for(Map.Entry<String,Object> entry:map.entrySet()){
            Object obj = entry.getValue();
            if(obj != null && obj instanceof String){
                String string = (String) obj;

                if(string.startsWith("[")){
                    List<?> list = depthConverList(string, mapper);
                    map.put(entry.getKey(), list);
                }else if (string.startsWith("{")) {
                    Map<String, Object> mapRecursion = depthConverMap(string, mapper);
                    map.put(entry.getKey(), mapRecursion);
                }
            }
        }
        return map;
    }

    /**
     * json转被对象引用的类型
     * @param json
     * @param typeReference 被转对象的引用类型
     * @param <E>
     * @return
     */
    public static <E> E jsonStrConverObject(String json, TypeReference<E> typeReference){
        try {
            return objectMapper.readValue(json,typeReference);
        } catch (IOException e) {
//            throw new JkznException(ExceptionEnum.JSON_PARSE_FAIL);
            throw new RuntimeException(e.getMessage());
        }
    }

    public static JavaType getJavaType(Class<?> collectionClazz,Class<?>...elementClazz){
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClazz, elementClazz);
        return javaType;
    }

}
